﻿using System;
using System.Collections.Generic;
using Mvc3App.Domain.Entities;
using Mvc3App.Domain.Repository;
using NHibernate;
using NHibernate.Criterion;

namespace Mvc3App.RepositoryNH
{
    public class BaseRepository<TEntity> : IRepository<TEntity, int> where TEntity : BaseEntity
    {
        protected readonly ISession Session;

        public BaseRepository()
        {
            Session = NHibernateHelper.OpenSession();
        }

        #region Implementation of IRepository<TEntity,int>

        public virtual TEntity GetOne(int id)
        {
            return Session.Get<TEntity>(id);
        }

        public void Add(TEntity entity)
        {
            using (ITransaction transaction = Session.BeginTransaction())
            {
                Session.Save(entity);
                transaction.Commit();
            }
        }

        public void Update(TEntity entity)
        {
            using (ITransaction transaction = Session.BeginTransaction())
            {
                Session.Update(entity);
                transaction.Commit();
            }
        }

        public void Delete(TEntity entity)
        {
            using (ITransaction transaction = Session.BeginTransaction())
            {
                if (!Session.Contains(entity))
                    Session.Load(entity, entity.Id);

                Session.Delete(entity);
                transaction.Commit();
            }
        }

        public long Count()
        {
            var criteria = Session.CreateCriteria<TEntity>();
            criteria.SetProjection(Projections.RowCount());

            var countMayBeInt32OrInt64DependingOnDatabase = criteria.UniqueResult();
            return Convert.ToInt64(countMayBeInt32OrInt64DependingOnDatabase);
        }

        public IEnumerable<TEntity> GetSlice(int slice, int quantity, string order, bool @ascending)
        {
            return Session.CreateCriteria<TEntity>()
                                .SetFirstResult(slice * quantity)
                                .SetMaxResults(quantity)
                                .AddOrder(new Order(order, ascending))
                                .List<TEntity>();
        }

        #endregion

        #region BaseRepository Methods

        public virtual IEnumerable<TEntity> GetAll(string orderByField, bool ascending)
        {
            return Session.CreateCriteria<TEntity>().AddOrder(new Order(orderByField, ascending)).List<TEntity>();
        }

        public virtual IEnumerable<TEntity> GetAll()
        {
            return Session.CreateCriteria<TEntity>().List<TEntity>();
        }

        #endregion
    }
}